/*
 * osc_state.c
 *
 * this stuff is thread safe
 *
 *  Created on: Oct 20, 2012
 *      Author: andrey
 */

#include "osc_state.h"
#include "rficonsole.h"

static Mutex osc_mtx;

static adc_snapshot osc_data;

int isHigh(adcsample_t level) {
	return level >= 2000;
}

void initOscState() {
	chMtxInit(&osc_mtx);
	osc_data.tail = 0;
}

void copy_adc_state(adc_state *source, adc_state *dest) {
	dest->time = source->time;
	for (int i = 0; i < ADC_NUMBER_CHANNELS; i++)
		dest->adc_data[i] = source->adc_data[i];
}

int isSameLevels(adc_state *adc1, adc_state *adc2) {
	for (int i = 0; i < ADC_NUMBER_CHANNELS; i++)
		if (isHigh(adc1->adc_data[i]) != isHigh(adc2->adc_data[i]))
			return FALSE;
	return TRUE;
}

volatile int adcSamplesCount = ADC_SAMLLES_INITIAL;

void setAdcSamplesCount(int value) {
	adcSamplesCount = value;
}

int getAdcSamplesCount() {
	return adcSamplesCount;
}

/**
 * external code should take care of sys locking!
 */
void addState(adc_state *source) {
	if (osc_data.tail == getAdcSamplesCount()) {
		// do nothing
	} else if (osc_data.tail == 0) {
		copy_adc_state(source, &osc_data.states[0]);
		osc_data.tail++;
	} else if (!isSameLevels(source, &osc_data.states[osc_data.tail - 1])) {
		copy_adc_state(source, &osc_data.states[osc_data.tail]);
		osc_data.tail++;
	}
}

void clearState(adc_state *state) {
	for (int i = 0; i < ADC_NUMBER_CHANNELS; i++)
		state->adc_data[i] = 0;
	state->time = 0;
}

void clearSnapshot(adc_snapshot *dest) {
	for (int i = 0; i < ADC_SAMPLES_COUNT; i++)
		clearState(&dest->states[i]);
	dest->tail = 0;
}

void resetSnapshot() {
	chSysLock()
	;
	clearSnapshot(&osc_data);
	chSysUnlock();
}

void copySnapshot(adc_snapshot *dest) {
	// ADC thread can only lock system, so we have to use same lock
	chSysLock()
	;

	for (int i = 0; i < getAdcSamplesCount(); i++)
		copy_adc_state(&osc_data.states[i], &dest->states[i]);
	dest->tail = osc_data.tail;
	chSysUnlock();
}

int findIndexForTime(time_t time, adc_snapshot *data) {
	if (data->tail == 0)
		return -1;
	if (time < data->states[0].time)
		return -2;
	for (int i = 1; i < data->tail; i++)
		if (data->states[i].time > time)
			return i - 1; // time is always not less than start time
	return -3; // time not found
}

void sort(int array[], int length) {

}

void printOscData(adc_snapshot *data) {
	print("printOscData tail=%d\r\n", data->tail);

	for (int ch = 0; ch < ADC_NUMBER_CHANNELS; ch++) {
		print("channel %d\r\n", ch);
		for (int sa = 0; sa < data->tail - 1; sa++) {
			int value = data->states[sa].adc_data[ch];
			int time = data->states[sa].time;

			int timeDiff = 0;
			if(sa > 0)
				timeDiff = data->states[sa].time - data->states[sa - 1].time;

			print("index %d time %d(%d) value %d\r\n", sa, time, timeDiff, value);
		}
	}

	if (data->tail < 2)
		return;

	for (int ch = 0; ch < ADC_NUMBER_CHANNELS; ch++) {
		int timeAccum = 0;

		for (int sa = 0; sa < data->tail - 2; sa++) {
			int value = data->states[sa].adc_data[ch];
			int time = data->states[sa].time;

			if (isHigh(value))
				timeAccum += data->states[sa + 1].time - time;
		}

		int total_time = data->states[data->tail - 1].time
				- data->states[0].time;
		int avg = total_time / data->tail;
		print("times for %d: acc=%d total %d avg %d\r\n", ch, timeAccum, total_time, avg);
	}
}

